﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.ZLog;
using UtilZ.Dotnet.Ex.Communication.Net.Telnet.Commands;
using UtilZ.Dotnet.Ex.Communication.Net.Telnet.KeyCommands;
using UtilZ.Dotnet.Ex.Communication.Net.FastTransfer;

namespace UtilZ.Dotnet.Ex.Communication.Net.Telnet
{
    internal partial class ListenTelnetClient
    {
        private List<string> _historyCommandList = new List<string>();
        public List<string> HistoryCommandList
        {
            get { return _historyCommandList; }
        }

        private int _historyCommandCapcity = 50;
        private int _historyCommandIndex = -1;

        private readonly StringBuilder _sbCommand = new StringBuilder();
        public StringBuilder SB
        {
            get { return _sbCommand; }
        }

        private int _cussorLocation = 0;



        /***************************************************************************************************
         * Telnet 连接建立时客户端首先发送的包
         * window
         * 255-251-1
         * 255-252-33-255-253-1-255-253-3
         * 
         * linux
         * 255-253-3-255-251-24-255-251-31-255-251-32-255-251-33-255-251-34-255-251-39-255-253-5-255-251-35
         * 255-252-1-255-253-1
         * 
         * mac
         * 255-251-37-255-253-3-255-251-24-255-251-31-255-251-32-255-251-33-255-251-34-255-251-39-255-253-5
         * 255-252-1-255-253-1
         ***************************************************************************************************/
        private OSPlatformID _platform = OSPlatformID.Linux_Unix;
        private bool _inited = false;
        private bool _authed = false;
        private TelnetUserInfo _userInfo = null;
        /// <summary>
        /// 登录用户信息，不用登录时为null
        /// </summary>
        public TelnetUserInfo UserInfo
        {
            get { return _userInfo; }
        }

        //private static byte[] _win = new byte[] { 255, 252, 33, 255, 253, 1, 255, 253, 3 };
        //private static byte[] _unix = new byte[] { 255, 253, 3, 255, 251, 24 };
        //private static byte[] _max = new byte[] { 255, 251, 37, 255, 253, 3 };

        private void ProcessReceiveData(byte[] data, int revicedDataLength)
        {
            if (revicedDataLength <= 0)
            {
                return;
            }

            //ZLoger.Info(string.Join("-", data.Take(revicedDataLength)));

            if (!this._inited)
            {
                //确定客户端操作系统,选择编码
                if (revicedDataLength == 3 && data[0] == 255 && data[1] == 251 && data[2] == 1)
                {
                    this._platform = OSPlatformID.Win;
                    try
                    {
                        this._messageEncoding = EncodingEx.GetEncoding("gb2312");
                    }
                    catch
                    {
                        this._messageEncoding = Encoding.Default;
                    }
                    this._inited = true;
                }
                else if (revicedDataLength == 27)
                {
                    if (data[0] == 255 && data[1] == 253 && data[2] == 3 && data[3] == 255 && data[4] == 251 && data[5] == 24)
                    {
                        this._platform = OSPlatformID.Linux_Unix;
                        this._messageEncoding = Encoding.UTF8;
                        this._inited = true;
                    }
                    else if (data[0] == 255 && data[1] == 251 && data[2] == 37 && data[3] == 255 && data[4] == 253 && data[5] == 3)
                    {
                        this._platform = OSPlatformID.MacOS;
                        this._messageEncoding = Encoding.UTF8;
                        this._inited = true;
                    }
                }

                if (this._inited)
                {
                    string echoStr;
                    if (this._authed)
                    {
                        echoStr = this._connectedPromptMessage + TelnetConstant.END_LINE_CURSOR;
                    }
                    else
                    {
                        echoStr = this._connectedPromptMessage + TelnetConstant.END_LINE_CURSOR + "account:" + TelnetConstant.END_LINE_CURSOR;
                    }

                    this.SendMessage(echoStr);//回显换行
                    //ZLoger.Warn(this._platform.ToString());
                    return;
                }
            }


            //大于0xF0为非内容
            if (data[0] >= 0xF0)
            {
                return;
            }

            //特殊按键(非字符按键)处理
            foreach (var keyCommand in TelnetKeyCommandManager.Commands)
            {
                if (keyCommand.Process(this, data, revicedDataLength))
                {
                    return;
                }
            }

            //增加内容
            this.Append(data, revicedDataLength);
        }

        private void Append(byte[] data, int revicedDataLength)
        {
            string inputStr = this._messageEncoding.GetString(data, 0, revicedDataLength);
            if (this._cussorLocation >= this._sbCommand.Length)
            {
                //追加
                this._sbCommand.Append(inputStr);
                this._cussorLocation += inputStr.Length;

                if (this._authed || this._userInfo == null)
                {
                    this.Send(data, 0, revicedDataLength);//回显
                }
                else
                {
                    this.Send(this._messageEncoding.GetBytes(new string('*', inputStr.Length)));
                }
            }
            else
            {
                //插入
                if (this._authed || this._userInfo == null)
                {
                    int cussorLocation = this._cussorLocation;
                    int delLen = this._sbCommand.Length - cussorLocation;
                    this.CurrsorMoveToEnd();
                    byte[] deleteCharInstruction = TelnetInstructions.GetDeleteCharInstruction(this._platform);
                    for (int i = 0; i < delLen; i++)
                    {
                        this.Send(deleteCharInstruction);
                    }

                    this._sbCommand.Insert(cussorLocation, inputStr);
                    this._cussorLocation += inputStr.Length;
                    string modStr = this._sbCommand.ToString(cussorLocation, delLen + inputStr.Length);
                    this.SendMessage(modStr);
                    this.LeftMoveCurrsor(delLen);
                }
                else
                {
                    //输入密码时,不允许移动光标
                }
            }
        }



        public void ClearChars()
        {
            this.CurrsorMoveToEnd();
            this.DeleteCurrsorLeftChars(this._sbCommand.Length);
            this._sbCommand.Clear();
        }

        public void DeleteCurrsorLeftChars(int chartCount)
        {
            if (this._cussorLocation <= 0)
            {
                return;
            }

            byte[] deleteCharInstruction = TelnetInstructions.GetDeleteCharInstruction(this._platform);
            if (this._cussorLocation >= this._sbCommand.Length)
            {
                //光标在输入文本末尾
                StringBuilder sb = this._sbCommand;
                for (int i = 0; i < chartCount; i++)
                {
                    if (sb.Length > 0 && this._cussorLocation > 0)
                    {
                        this._cussorLocation--;
                        sb.Remove(sb.Length - 1, 1);
                        this.Send(deleteCharInstruction);
                    }
                }
            }
            else
            {
                //光标在输入文本中间
                int cussorLocation = this._cussorLocation;
                this.CurrsorMoveToEnd();
                for (int i = 0; i < this._sbCommand.Length; i++)
                {
                    this.Send(deleteCharInstruction, 0, deleteCharInstruction.Length);
                }
                int newCussorLocation = cussorLocation - chartCount;
                this._sbCommand.Remove(newCussorLocation, chartCount);
                string newStr = this._sbCommand.ToString();
                this.SendMessage(newStr);

                this.CurrsorMoveToHome();
                this.PrimitiveRightMoveCurrsor(newCussorLocation + 1);
                this._cussorLocation += newCussorLocation;
            }
        }



        public void DeleteCurrsorRightChars(int chartCount)
        {
            int cussorLocation = this._cussorLocation;
            if (this._sbCommand.Length == 0 || cussorLocation >= this._sbCommand.Length)
            {
                return;
            }

            int changeCharCount = this._sbCommand.Length - cussorLocation;
            int rightDelCharCount = changeCharCount - 1;
            string modStr = this._sbCommand.ToString(cussorLocation + 1, rightDelCharCount);
            this.CurrsorMoveToEnd();

            byte[] deleteCharInstruction = TelnetInstructions.GetDeleteCharInstruction(this._platform);
            for (int i = 0; i < changeCharCount; i++)
            {
                this.Send(deleteCharInstruction);
            }

            this._sbCommand.Remove(cussorLocation, 1);
            this.SendMessage(modStr);
            this.PrimitiveLeftMoveCurrsor(modStr.Length);
            this._cussorLocation = cussorLocation;
        }

        public void LeftMoveCurrsor(int charCount)
        {
            this.PrimitiveLeftMoveCurrsor(charCount);
            this._cussorLocation -= charCount;
        }

        private void PrimitiveLeftMoveCurrsor(int charCount)
        {
            byte[] leftMoveCurrsorInstruction = TelnetInstructions.GetLeftArrow(this._platform);
            for (int i = 0; i < charCount; i++)
            {
                this.Send(leftMoveCurrsorInstruction, 0, leftMoveCurrsorInstruction.Length);
            }
        }

        public void RightMoveCurrsor(int charCount)
        {
            this.PrimitiveRightMoveCurrsor(charCount);
            this._cussorLocation += charCount;
        }

        private void PrimitiveRightMoveCurrsor(int charCount)
        {
            byte[] rightMoveCurrsorInstruction = TelnetInstructions.GetRightArrow(this._platform);
            for (int i = 0; i < charCount; i++)
            {
                this.Send(rightMoveCurrsorInstruction, 0, rightMoveCurrsorInstruction.Length);
            }
        }

        public void CurrsorMoveToHome()
        {
            this.LeftMoveCurrsor(this._cussorLocation);
        }

        public void CurrsorMoveToEnd()
        {
            this.RightMoveCurrsor(this._sbCommand.Length - this._cussorLocation);
        }





        public void EchoPreCommand()
        {
            if (this._historyCommandList.Count == 0)
            {
                return;
            }

            this.ClearChars();

            this._historyCommandIndex--;
            if (this._historyCommandIndex < 0)
            {
                this._historyCommandIndex = this._historyCommandList.Count - 1;
            }

            string historyCommand = this._historyCommandList[this._historyCommandIndex];
            this._sbCommand.Append(historyCommand);
            this._cussorLocation = this._sbCommand.Length;
            this.SendMessage(historyCommand);
        }

        public void EchoNextCommand()
        {
            if (this._historyCommandList.Count == 0)
            {
                return;
            }

            this.ClearChars();

            this._historyCommandIndex++;
            if (this._historyCommandIndex >= this._historyCommandList.Count)
            {
                this._historyCommandIndex = 0;
            }

            string historyCommand = this._historyCommandList[this._historyCommandIndex];
            this._sbCommand.Append(historyCommand);
            this._cussorLocation = this._sbCommand.Length;
            this.SendMessage(historyCommand);
        }

        public void ApprowLeftMove(byte[] data, int revicedDataLength)
        {
            int newCussorLocation = this._cussorLocation - 1;
            if (newCussorLocation >= 0)
            {
                this._cussorLocation = newCussorLocation;
                this.Send(data, 0, revicedDataLength);
                // telnetClient.Send(new byte[] { data[0] });
                //this.Send(new byte[] { 0x08, 0x20, 0x08 });
            }
        }

        public void ApprowRigtMove(byte[] data, int revicedDataLength)
        {
            int newCussorLocation = this._cussorLocation + 1;
            if (newCussorLocation <= this._sbCommand.Length)
            {
                this._cussorLocation = newCussorLocation;
                this.Send(data, 0, revicedDataLength);

                //telnetClient.Send(new byte[] { data[0] });
                //this.Send(new byte[] { 0x08, 0x20, 0x08 });
            }
        }




        #region 消息处理
        public void ProcessMessage()
        {
            if (this._sbCommand.Length > 0)
            {
                string message = this._sbCommand.ToString().Trim();
                this._sbCommand.Clear();
                this._cussorLocation = 0;

                if (!this._authed)
                {
                    this.Auth(message);
                    return;
                }

                if (string.IsNullOrWhiteSpace(message))
                {
                    return;
                }

                int index = this._historyCommandList.IndexOf(message);
                if (index >= 0 && index != this._historyCommandList.Count - 1)
                {
                    this._historyCommandList.RemoveAt(index);
                }

                if (!this._historyCommandList.Contains(message))
                {
                    this._historyCommandList.Add(message);

                    while (this._historyCommandCapcity >= 0 && this._historyCommandList.Count > this._historyCommandCapcity)
                    {
                        this._historyCommandList.RemoveAt(0);
                    }

                    this._historyCommandIndex = this._historyCommandList.Count;
                }

                //内部命令处理
                if (!this.ProcessInnerCommand(message))
                {
                    //外部命令处理
                    string result = this._processMessage(new TelnetMessageArgs(this, message));
                    result = $"{TelnetConstant.END_LINE_CURSOR}{result}{TelnetConstant.END_LINE_CURSOR}";
                    this.SendMessage(result);
                }
            }
            else
            {
                this.SendMessage(TelnetConstant.END_LINE_CURSOR);
            }

            //命令执行后,保证终端上按上方向键盘返回前一次执行的命令文本
            if (this._historyCommandList.Count > 0)
            {
                this._historyCommandIndex = 0;
            }
        }


        private void Auth(string message)
        {
            string echoStr;
            if (this._userInfo == null)
            {
                this._userInfo = this._checkAccount(message);
                if (this._userInfo == null)
                {
                    echoStr = "user does not exist..." + TelnetConstant.END_LINE_CURSOR + "account:" + TelnetConstant.END_LINE_CURSOR;
                }
                else
                {
                    echoStr = "password:" + TelnetConstant.END_LINE_CURSOR;
                }
            }
            else
            {
                if (string.Equals(this._userInfo.Password, message))
                {
                    this._authed = true;
                    echoStr = "telnet login success..." + TelnetConstant.END_LINE_CURSOR;
                }
                else
                {
                    this._userInfo = null;
                    echoStr = "password invalid..." + TelnetConstant.END_LINE_CURSOR + "account:" + TelnetConstant.END_LINE_CURSOR;
                }
            }

            echoStr = TelnetConstant.END_LINE + echoStr;
            this.SendMessage(echoStr);
        }


        private readonly char[] _splitChArr = new char[] { ' ' };
        private bool ProcessInnerCommand(string command)
        {
            command = command.ToLower();
            if (!command.StartsWith(TelnetCommandConstant.TSET))
            {
                return false;
            }

            //tset -e utf-8
            string[] paraArr = command.Split(this._splitChArr, StringSplitOptions.RemoveEmptyEntries);
            if (paraArr.Length < 2)
            {
                this.SendCommandInvalid();
                return false;
            }

            if (!string.Equals(paraArr[0], TelnetCommandConstant.TSET))
            {
                this.SendCommandInvalid();
                return false;
            }

            ITelnetCommand telnetCommand;
            if (TelnetCommandManager.TryGetTelnetCommand(paraArr[1], out telnetCommand))
            {
                return telnetCommand.Excute(this, paraArr);
            }
            else
            {
                //this.SendCommandInvalid();
                return false;
            }
        }


        private void SendCommandInvalid()
        {
            string result = $"{TelnetConstant.CURSOR}{TelnetCommandConstant.TSET} command invalid,-h help{TelnetConstant.END_LINE_CURSOR}";
            this.SendMessage(result);
        }

        public void SendClear()
        {
            this.SendMessage("\u001B[1J\u001B[H");//回显清空
        }
        #endregion

    }
}
